﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VectorMath;
using System.Xml;
using System.IO;
using System.Text.RegularExpressions;
using log4net;

namespace DOEgbXML
{
    public class gbXMLSpaces
    {
        string id;
        PlanarGeometry pg;
        ShellGeometry sg;
        List<SpaceBoundary> spacebounds;
        string CADObjectID;

        public class PlanarGeometry
        {
            public PolyLoop pl;

        }

        public class ShellGeometry
        {
            public string id;
            public ClosedShell cs;
        }

        public class ClosedShell
        {
            public List<PolyLoop> ploops;
        }

        public class SpaceBoundary
        {
            public string surfaceIdRef;
            public string ifcGUID;
            public bool isSecondLevelBoundary;
            public string oppositeIdRef;
            public PlanarGeometry sbplane;

        }

        public class PolyLoop
        {
            public List<Vector.MemorySafe_CartCoord> plcoords;

        }

        public static List<gbXMLSpaces> getSimpleSpaces(XmlDocument xmldoc, XmlNamespaceManager xmlns)
        {
            List<gbXMLSpaces> retspaces = new List<gbXMLSpaces>();
            try
            {
                XmlNodeList nodes = xmldoc.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space", xmlns);

                foreach (XmlNode spaceNode in nodes)
                {
                    //initialize a new instance of the class
                    gbXMLSpaces space = new gbXMLSpaces();
                    space.spacebounds = new List<SpaceBoundary>();
                    //get id and space
                    XmlAttributeCollection spaceAtts = spaceNode.Attributes;
                    foreach (XmlAttribute at in spaceAtts)
                    {
                        if (at.Name == "id")
                        {
                            space.id = at.Value;
                            break;
                        }
                    }
                    if (spaceNode.HasChildNodes)
                    {
                        XmlNodeList childNodes = spaceNode.ChildNodes;
                        foreach (XmlNode node in childNodes)
                        {
                            if (node.Name == "PlanarGeometry")
                            {
                                space.pg = new PlanarGeometry();
                                XmlNodeList childnodes = node.ChildNodes;
                                foreach (XmlNode node2 in childnodes)
                                {
                                    if (node2.Name == "PolyLoop")
                                    {
                                        space.pg.pl = new PolyLoop();
                                        space.pg.pl.plcoords = new List<Vector.MemorySafe_CartCoord>();

                                        XmlNodeList cartPoints = node2.ChildNodes;
                                        foreach (XmlNode point in cartPoints)
                                        {
                                            if (point.Name == "CartesianPoint")
                                            {
                                                Vector.CartCoord coord = new Vector.CartCoord();
                                                XmlNodeList val = point.ChildNodes;
                                                int pointcount = 1;
                                                foreach (XmlNode cpoint in val)
                                                {
                                                    switch (pointcount)
                                                    {
                                                        case 1:
                                                            coord.X = Convert.ToDouble(cpoint.InnerText);
                                                            break;
                                                        case 2:
                                                            coord.Y = Convert.ToDouble(cpoint.InnerText);
                                                            break;
                                                        case 3:
                                                            coord.Z = Convert.ToDouble(cpoint.InnerText);
                                                            break;
                                                    }
                                                    pointcount++;
                                                }
                                                Vector.MemorySafe_CartCoord memsafecoord = Vector.convertToMemorySafeCoord(coord);
                                                space.pg.pl.plcoords.Add(memsafecoord);
                                            }
                                        }
                                    }
                                }
                            }
                            else if (node.Name == "ShellGeometry")
                            {
                                space.sg = new ShellGeometry();
                                XmlAttributeCollection sgAtts = spaceNode.Attributes;
                                foreach (XmlAttribute at in sgAtts)
                                {
                                    if (at.Name == "id")
                                    {
                                        space.sg.id = at.Value;
                                        break;
                                    }
                                }

                                XmlNodeList childnodes = node.ChildNodes;
                                foreach (XmlNode sgnode in childnodes)
                                {
                                    if (sgnode.Name == "ClosedShell")
                                    {
                                        space.sg.cs = new ClosedShell();
                                        space.sg.cs.ploops = new List<PolyLoop>();

                                        foreach (XmlNode pl in sgnode)
                                        {
                                            if (pl.Name == "PolyLoop")
                                            {
                                                PolyLoop sgpl = new PolyLoop();
                                                sgpl.plcoords = new List<Vector.MemorySafe_CartCoord>();
                                                XmlNodeList cartPoints = pl.ChildNodes;
                                                foreach (XmlNode point in cartPoints)
                                                {
                                                    if (point.Name == "CartesianPoint")
                                                    {
                                                        Vector.CartCoord coord = new Vector.CartCoord();
                                                        XmlNodeList val = point.ChildNodes;
                                                        int pointcount = 1;
                                                        foreach (XmlNode cpoint in val)
                                                        {
                                                            switch (pointcount)
                                                            {
                                                                case 1:
                                                                    coord.X = Convert.ToDouble(cpoint.InnerText);
                                                                    break;
                                                                case 2:
                                                                    coord.Y = Convert.ToDouble(cpoint.InnerText);
                                                                    break;
                                                                case 3:
                                                                    coord.Z = Convert.ToDouble(cpoint.InnerText);
                                                                    break;
                                                            }
                                                            pointcount++;
                                                        }
                                                        Vector.MemorySafe_CartCoord memsafecoord = Vector.convertToMemorySafeCoord(coord);
                                                        sgpl.plcoords.Add(memsafecoord);
                                                    }
                                                }
                                                space.sg.cs.ploops.Add(sgpl);
                                            }
                                        }
                                    }
                                }
                            }
                            else if (node.Name == "SpaceBoundary")
                            {
                                SpaceBoundary sb = new SpaceBoundary();
                                XmlAttributeCollection spbatts = node.Attributes;
                                foreach (XmlAttribute at in spbatts)
                                {
                                    if (at.Name == "surfaceIdRef")
                                    {
                                        sb.surfaceIdRef = at.Value;
                                        break;
                                    }
                                }
                                XmlNodeList sbchilds = node.ChildNodes;
                                foreach (XmlNode sbpnode in sbchilds)
                                {
                                    if (sbpnode.Name == "PlanarGeometry")
                                    {
                                        sb.sbplane = new PlanarGeometry();
                                        XmlNodeList pgchilds = sbpnode.ChildNodes;
                                        foreach (XmlNode pgchild in pgchilds)
                                        {
                                            if (pgchild.Name == "PolyLoop")
                                            {
                                                sb.sbplane.pl = new PolyLoop();

                                                sb.sbplane.pl.plcoords = new List<Vector.MemorySafe_CartCoord>();
                                                XmlNodeList cartPoints = pgchild.ChildNodes;
                                                foreach (XmlNode point in cartPoints)
                                                {
                                                    if (point.Name == "CartesianPoint")
                                                    {
                                                        Vector.CartCoord coord = new Vector.CartCoord();
                                                        XmlNodeList val = point.ChildNodes;
                                                        int pointcount = 1;
                                                        foreach (XmlNode cpoint in val)
                                                        {
                                                            switch (pointcount)
                                                            {
                                                                case 1:
                                                                    coord.X = Convert.ToDouble(cpoint.InnerText);
                                                                    break;
                                                                case 2:
                                                                    coord.Y = Convert.ToDouble(cpoint.InnerText);
                                                                    break;
                                                                case 3:
                                                                    coord.Z = Convert.ToDouble(cpoint.InnerText);
                                                                    break;
                                                            }
                                                            pointcount++;
                                                        }
                                                        Vector.MemorySafe_CartCoord memsafecoord = Vector.convertToMemorySafeCoord(coord);
                                                        sb.sbplane.pl.plcoords.Add(memsafecoord);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                                //finally, add the thing here
                                space.spacebounds.Add(sb);
                            }
                        }
                    }
                    else
                    {
                        //throw something
                    }
                    retspaces.Add(space);
                }
            }
            catch (Exception e)
            {

            }
            return retspaces;
        }

        public static DOEgbXMLReportingObj SpaceSurfacesCCTest(List<gbXMLSpaces> spaces, DOEgbXMLReportingObj report)
        {
            //this summary is text that describes to a lay user what this test does, and how it works functionally.  The user should have some familiarity with the basic knowledge of gbXML 
            //added Feb 17 2014
            report.testSummary = "This test ensures that all surface coordinates are listed in a counterclockwise order.  This is a requirement of all gbXML PolyLoop definitions";
            report.MessageList = new List<string>();
            report.TestPassedDict = new Dictionary<string, bool>();
            try
            {
                report.MessageList.Add("Beginning test to check the winding order of all polyloops that describe surfaces of each Space object.");
                report.MessageList.Add("All coordinates should be wound in a counter-clockwise order.");
                
                foreach (DOEgbXML.gbXMLSpaces space in spaces)
                {
                    bool spacepassorfail = true;
                    report.MessageList.Add("Testing Space id: " + space.id + " Shell Geometry PolyLoops.");
                    for (int sgsurfcount = 0; sgsurfcount < space.sg.cs.ploops.Count; sgsurfcount++)
                    {
                        PolyLoop pl = space.sg.cs.ploops[sgsurfcount];
                        var wd = Vector.isCounterClockwise(pl.plcoords);
                        if (wd == Vector.WalkDirection.Clockwise)
                        {
                            report.MessageList.Add("CLOCKWISE WINDING DETECTED: Shell Geometry surface number " + (sgsurfcount+1) + " is wound in a clockwise order.");
                            string t = space.id + "-sg-" + sgsurfcount.ToString();
                            report.TestPassedDict.Add(t, false);
                            spacepassorfail = false;
                        }
                        else
                        {
                            report.MessageList.Add("PASS: Shell Geometry surface number " + (sgsurfcount+1) + " is wound in a counterclockwise order.");
                            string t = space.id + "-sg-" + sgsurfcount.ToString();
                            report.TestPassedDict.Add(t, true);
                        }
                    }

                    foreach (SpaceBoundary sb in space.spacebounds)
                    {
                        PolyLoop pl = sb.sbplane.pl;
                        var wd = Vector.isCounterClockwise(pl.plcoords);
                        if (wd == Vector.WalkDirection.Clockwise)
                        {
                            report.MessageList.Add("CLOCKWISE WINDING DETECTED: Surface Boundary with id " + sb.surfaceIdRef + " is wound in a clockwise order.");
                            string t = space.id + "-" + sb.surfaceIdRef;
                            report.TestPassedDict.Add(t, false);
                            spacepassorfail = false;
                        }
                        else
                        {
                            report.MessageList.Add("OK: Surface Boundary with id " + sb.surfaceIdRef + " is wound in a counterclockwise order.");
                            string t = space.id + "-" + sb.surfaceIdRef;
                            report.TestPassedDict.Add(t, true);
                        }
                    }
                    if (spacepassorfail) { report.TestPassedDict.Add(space.id, true); }
                    else { report.TestPassedDict.Add(space.id, false); }

                }
            }
            catch (Exception e)
            {
                report.longMsg = e.ToString();
                report.MessageList.Add("This test failed unexpectedly.");
                report.passOrFail = false;
                return report;
            }
            if (report.TestPassedDict.ContainsValue(false))
            {
                report.longMsg = "This test found errors in the geometry when testing the winding order of the Space elements surfaces.  See below for details.";
                report.passOrFail = false;
            }
            else
            {
                report.longMsg = "This test did not find any errors in the geometry when testing the winding order of the Space elements surfaces.  See below for details.";
                report.passOrFail = true;
            }
            return report;
        }

        public static DOEgbXMLReportingObj SpaceSurfacesSelfIntersectionTest(List<gbXMLSpaces> spaces, DOEgbXMLReportingObj report)
        {
            //this summary is text that describes to a lay user what this test does, and how it works functionally.  The user should have some familiarity with the basic knowledge of gbXML 
            //added Feb 17 2014
            report.testSummary = "This test ensures that each surface, defined inside the gbXML Space element, is not self-intersecting.";
            report.MessageList = new List<string>();
            report.TestPassedDict = new Dictionary<string, bool>();
            try
            {
                report.MessageList.Add("Beginning test to check each PolyLoop of Space objects to ensure they do not form self-intersecting polygons.");
                report.MessageList.Add("Self-intersecting polygons are not allowed.");
                
                foreach (DOEgbXML.gbXMLSpaces space in spaces)
                {
                    bool spacepassorfail = true;
                    report.MessageList.Add("Testing Space id: " + space.id + " Shell Geometry PolyLoops.");
                    for (int sgsurfcount = 1; sgsurfcount <= space.sg.cs.ploops.Count; sgsurfcount++)
                    {
                        PolyLoop pl = space.sg.cs.ploops[sgsurfcount];
                        var wd = Vector.isCounterClockwise(pl.plcoords);
                        if (Vector.BruteForceIntersectionTest(pl.plcoords))
                        {
                            report.MessageList.Add("PASS: Shell Geometry surface number " + sgsurfcount + " is not self-intersecting.");
                            string t = space.id + "-sg-" + sgsurfcount.ToString();
                            report.TestPassedDict.Add(t, true);
                        }
                        else
                        {
                            report.MessageList.Add("SELF INTERSECTION DETECTED: Shell Geometry surface number " + sgsurfcount + " is self-intersecting.");
                            string t = space.id + "-sg-" + sgsurfcount.ToString();
                            report.TestPassedDict.Add(t, false);
                            spacepassorfail = false;
                        }
                    }

                    foreach (SpaceBoundary sb in space.spacebounds)
                    {
                        PolyLoop pl = sb.sbplane.pl;
                        var wd = Vector.isCounterClockwise(pl.plcoords);
                        if (Vector.BruteForceIntersectionTest(pl.plcoords))
                        {
                            report.MessageList.Add("PASS: Surface Boundary with id " + sb.surfaceIdRef + " is not self-intersecting.");
                            string t = space.id + "-" + sb.surfaceIdRef;
                            report.TestPassedDict.Add(t, true);
                        }
                        else
                        {
                            report.MessageList.Add("SELF INTERSECTION DETECTED: Surface Boundary with id " + sb.surfaceIdRef + " is self-intersecting.");
                            string t = space.id + "-" + sb.surfaceIdRef;
                            report.TestPassedDict.Add(t, false);
                            spacepassorfail = false;
                        }
                    }
                    if (spacepassorfail) { report.TestPassedDict.Add(space.id, true); }
                    else { report.TestPassedDict.Add(space.id, false); }

                }
            }
            catch (Exception e)
            {
                report.longMsg = e.ToString();
                report.MessageList.Add("This test failed unexpectedly.");
                report.passOrFail = false;
                return report;
            }
            return report;
        }

        public static DOEgbXMLReportingObj UniqueSpaceIdTest(XmlDocument gbXMLDoc, XmlNamespaceManager gbXMLnsm, DOEgbXMLReportingObj report)
        {
            //this summary is text that describes to a lay user what this test does, and how it works functionally.  The user should have some familiarity with the basic knowledge of gbXML 
            //added Feb 13 2013
            report.testSummary = "This test reviews the values if all Space id attributes, and ensures that they are all unique.  ";
            report.testSummary += "If there are any duplicate Space id values, then this test will fail.  If there are duplicates, the remainder of the tests in the testbed are not executed and the test will end here until the test file is properly updated.  Each Space id should be unique in valid gbXML.  If this test has failed, you may take the following actions.";

            report.MessageList = new List<string>();
            report.TestPassedDict = new Dictionary<string, bool>();
            List<string> spaceIdList = new List<string>();
            report.standResult = new List<string>();
            report.testResult = new List<string>();
            report.idList = new List<string>();
            // report.testType = "UniqueId";
            try
            {
                XmlNodeList nodes = gbXMLDoc.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space", gbXMLnsm);
                foreach (XmlNode node in nodes)
                {
                    //looks to see if the spaceId is already included in the list of space IDs being generated
                    string spaceId;
                    spaceId = node.Attributes[0].Value.ToString();
                    if(spaceIdList.Contains(spaceId))
                    {
                        //not unique
                        report.MessageList.Add("SpaceID: "+ spaceId + " is not unique." );
                        report.longMsg = "This test for unique space id attributes has failed.  All Space Id attributes should be unique.";
                        report.passOrFail = false;
                    }
                    spaceIdList.Add(spaceId);
                    report.MessageList.Add("SpaceID: " + spaceId + " is unique.");
                }
                if (report.passOrFail)
                {
                    report.longMsg = "TEST PASSED: All spaces have unique id attributes.";
                    report.passOrFail = true;
                }
                else
                {
                    report.longMsg = "TEST FAILED: All spaces do not have unique Ids.";
                }

            }
            catch (Exception e)
            {
                report.longMsg = e.ToString();
                report.MessageList.Add("This test unexpectedly failed.");
                report.passOrFail = false;
                return report;
            }
            return report;
        }

        public static DOEgbXMLReportingObj UniqueSpaceBoundaryIdTest(XmlDocument gbXMLDoc, XmlNamespaceManager gbXMLnsm, DOEgbXMLReportingObj report)
        {
            //this summary is text that describes to a lay user what this test does, and how it works functionally.  The user should have some familiarity with the basic knowledge of gbXML 
            //added Feb 13 2013
            report.testSummary = "This test reviews the values if all SpaceBoundary surfaceIdRef attributes, and ensures that they are all unique.  ";
            report.testSummary += "If there are any duplicate SpaceBoundary surfaceIdRef values, then this test will fail.  If there are duplicates, the remainder of the tests in the testbed are not executed and the test will end here until the test file is properly updated.  Each SpaceBoundary surfaceIdRef should be unique in valid gbXML.  If this test has failed, you may take the following actions.";

            report.MessageList = new List<string>();
            report.TestPassedDict = new Dictionary<string, bool>();
            List<string> spaceIdList = new List<string>();
            report.standResult = new List<string>();
            report.testResult = new List<string>();
            report.idList = new List<string>();
            // report.testType = "UniqueId";
            try
            {
                XmlNodeList nodes = gbXMLDoc.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space/gbXMLv5:SpaceBoundary", gbXMLnsm);
                foreach (XmlNode node in nodes)
                {
                    //looks to see if the SpaceBoundaryId is already included in the list of SpaceBoundary IDs being generated
                    string spaceboundaryId;
                    spaceboundaryId = node.Attributes[0].Value.ToString();
                    if (spaceIdList.Contains(spaceboundaryId))
                    {
                        //not unique
                        report.MessageList.Add("SpaceBoundary surfaceIdRef: " + spaceboundaryId + " is not unique.");
                        report.longMsg = "This test for unique SpaceBoundary surfaceIdRef attributes has failed.  All SpaceBoundary surfaceIdRef attributes should be unique.";
                        report.passOrFail = false;
                    }
                    spaceIdList.Add(spaceboundaryId);
                    report.MessageList.Add("SpaceBoundary surfaceIdRef: " + spaceboundaryId + " is unique.");
                }
                if(report.passOrFail)
                {
                    report.longMsg = "TEST PASS: All SpaceBoundary surfaceIdRefs attributes have unique values.";
                    report.passOrFail = true;
                }
                else
                {
                    report.longMsg = "TEST FAIL: SpaceBoundary surfaceIdRefs attributes are not all unique.";
                    report.passOrFail = false;
                }

            }
            catch (Exception e)
            {
                report.longMsg = e.ToString();
                report.MessageList.Add("This test unexpectedly failed.");
                report.passOrFail = false;
                return report;
            }
            return report;
        }

        public static DOEgbXMLReportingObj SurfaceDefsCounterClock(List<gbXMLSpaces> spaces, DOEgbXMLReportingObj report)
        {
            //this summary is text that describes to a lay user what this test does, and how it works functionally.  The user should have some familiarity with the basic knowledge of gbXML 
            //added Feb 13 2013
            report.testSummary = "This test reviews all of the surface that make up a space, and simply tries to determine if";
            report.testSummary += " the polygons are defined by coordinates that wind in a counterclockwise order.";

            report.MessageList = new List<string>();
            report.TestPassedDict = new Dictionary<string, bool>();
            try
            {
                foreach (gbXMLSpaces space in spaces)
                {
                     
                }
            }
            catch (Exception e)
            {

            }
            return report;
        }

        public static List<SpaceBoundary> GetSpaceBoundaryList(XmlDocument gbXMLDoc, XmlNamespaceManager gbXMLnsm)
        {

            
            List<SpaceBoundary> sbList = new List<SpaceBoundary>();
            try
            {
                XmlNodeList nodes = gbXMLDoc.SelectNodes("/gbXMLv5:gbXML/gbXMLv5:Campus/gbXMLv5:Building/gbXMLv5:Space/gbXMLv5:SpaceBoundary", gbXMLnsm);
                foreach (XmlNode node in nodes)
                {
                    SpaceBoundary sb = new SpaceBoundary();
                    string spaceboundaryId;
                    spaceboundaryId = node.Attributes[0].Value.ToString();
                    sb.surfaceIdRef = spaceboundaryId;

                    XmlNodeList sbchilds = node.ChildNodes;
                    foreach (XmlNode sbpnode in sbchilds)
                    {
                        if (sbpnode.Name == "PlanarGeometry")
                        {
                            sb.sbplane = new PlanarGeometry();
                            XmlNodeList pgchilds = sbpnode.ChildNodes;
                            MakeSBPlanarGeometry(sb, pgchilds);
                        }
                    }

                    sbList.Add(sb);
                }
            }
            catch (Exception e)
            {
                throw e;
            }
            return sbList;
        }

        private static SpaceBoundary MakeSBPlanarGeometry(SpaceBoundary sb, XmlNodeList pgchilds)
        {
            try
            {

                foreach (XmlNode pgchild in pgchilds)
                {
                    if (pgchild.Name == "PolyLoop")
                    {
                        sb.sbplane.pl = new PolyLoop();

                        sb.sbplane.pl.plcoords = new List<Vector.MemorySafe_CartCoord>();
                        XmlNodeList cartPoints = pgchild.ChildNodes;
                        foreach (XmlNode point in cartPoints)
                        {
                            if (point.Name == "CartesianPoint")
                            {
                                Vector.CartCoord coord = new Vector.CartCoord();
                                XmlNodeList val = point.ChildNodes;
                                int pointcount = 1;
                                foreach (XmlNode cpoint in val)
                                {
                                    switch (pointcount)
                                    {
                                        case 1:
                                            coord.X = Convert.ToDouble(cpoint.InnerText);
                                            break;
                                        case 2:
                                            coord.Y = Convert.ToDouble(cpoint.InnerText);
                                            break;
                                        case 3:
                                            coord.Z = Convert.ToDouble(cpoint.InnerText);
                                            break;
                                    }
                                    pointcount++;
                                }
                                Vector.MemorySafe_CartCoord memsafecoord = Vector.convertToMemorySafeCoord(coord);
                                sb.sbplane.pl.plcoords.Add(memsafecoord);
                            }
                        }
                    }
                }
            }
            catch (Exception e)
            {

            }
            return sb;
        }

        public static DOEgbXMLReportingObj SpaceSurfacesPlanarTest(List<gbXMLSpaces> Spaces, DOEgbXMLReportingObj report)
        {
            report.MessageList = new List<string>();
            //ensure that each set of RHR tests result in parallel or anti-parallel resultant vectors, or else fail the test
            try
            {
                foreach (gbXMLSpaces s in Spaces)
                {
                    //test shell geometry's closed shell polyloop planarity
                    var ploops = s.sg.cs.ploops;
                    Dictionary<string, List<Vector.CartVect>> surfaceXProducts = new Dictionary<string, List<Vector.CartVect>>();
                    
                    int plcount = 1;
                    bool spacepassorfail = true;
                    foreach (var pl in ploops)
                    {
                        List<Vector.CartVect> xProducts = new List<Vector.CartVect>();
                        for (int i = 0; i < pl.plcoords.Count() - 2; i++)
                        {
                            //Get the Cross Product
                            VectorMath.Vector.CartVect v1 = VectorMath.Vector.CreateVector(pl.plcoords[i], pl.plcoords[i + 1]);
                            VectorMath.Vector.CartVect v2 = VectorMath.Vector.CreateVector(pl.plcoords[i + 1], pl.plcoords[i + 2]);
                            Vector.CartVect xProd = Vector.CrossProduct(v1, v2);
                            xProd = Vector.UnitVector(xProd);
                            xProducts.Add(xProd);
                        }
                        //give the polyloops some identifier, since they technically don't contain one
                        string ploopname = s.id + "*_*" + plcount.ToString();
                        surfaceXProducts.Add(ploopname, xProducts);
                        for (int j = 0; j < xProducts.Count - 1; j++)
                        {
                            report.MessageList.Add("Planarity Test for Shell Geometry :" + ploopname);
                            //parallel and anti parallel
                            if (xProducts[j].X == xProducts[j + 1].X && xProducts[j].Y == xProducts[j + 1].Y && xProducts[j].Z == xProducts[j + 1].Z)
                            {
                                report.MessageList.Add("PASS: Coordinates for this surface form a perfectly planar surface.");
                                report.TestPassedDict.Add(ploopname, true);
                                continue;
                            }
                            //anti-parallel
                            else if (xProducts[j].X == -1 * xProducts[j + 1].X && xProducts[j].Y == -1 * xProducts[j + 1].Y && xProducts[j].Z == -1 * xProducts[j + 1].Z)
                            {
                                report.MessageList.Add("PASS: Coordinates for this surface form a perfectly planar surface.");
                                report.TestPassedDict.Add(ploopname, true);
                                continue;
                            }
                            //I defined these tolerances myself.  Could this be done better?
                            else if (Math.Abs(xProducts[j].X) - Math.Abs(xProducts[j + 1].X) < 0.0001 && Math.Abs(xProducts[j].Y) - Math.Abs(xProducts[j + 1].Y) < 0.0001 &&
                                Math.Abs(xProducts[j].Z) - Math.Abs(xProducts[j + 1].Z) < 0.0001)
                            {
                                report.MessageList.Add("Coordinates for this surface form a nearly planar surface that is within allowable tolerances.");
                                report.TestPassedDict.Add(ploopname, true);
                                continue;
                            }
                            else
                            {
                                report.MessageList.Add("NON PLANAR SURFACE DETECTED:  Coordinates for this surface do not appear to form a planar surface.");
                                report.TestPassedDict.Add(ploopname, false);
                                spacepassorfail = false;
                            }
                        }
                        //next polyloop please
                        plcount++;
                    }

                    //test the space boundary planarity
                    var sbs = s.spacebounds;
                    Dictionary<string, List<Vector.CartVect>> sbXProducts = new Dictionary<string, List<Vector.CartVect>>();
                    foreach (var sb in sbs)
                    {
                        report.MessageList.Add("Planarity Test for Space Boundary: " + sb.surfaceIdRef);
                        var ploop = sb.sbplane.pl;
                        List<Vector.CartVect> xProducts = new List<Vector.CartVect>();
                        for (int i = 0; i < ploop.plcoords.Count() - 2; i++)
                        {
                            //Get the Cross Product
                            VectorMath.Vector.CartVect v1 = VectorMath.Vector.CreateVector(ploop.plcoords[i], ploop.plcoords[i + 1]);
                            VectorMath.Vector.CartVect v2 = VectorMath.Vector.CreateVector(ploop.plcoords[i + 1], ploop.plcoords[i + 2]);
                            Vector.CartVect xProd = Vector.CrossProduct(v1, v2);
                            xProd = Vector.UnitVector(xProd);
                            xProducts.Add(xProd);
                        }
                        //a name for the Space Boundary is already contained in the surfaceIdRef
                        sbXProducts.Add(sb.surfaceIdRef, xProducts);
                        for (int j = 0; j < xProducts.Count - 1; j++)
                        {
                            //parallel and anti parallel
                            if (xProducts[j].X == xProducts[j + 1].X && xProducts[j].Y == xProducts[j + 1].Y && xProducts[j].Z == xProducts[j + 1].Z)
                            {
                                report.MessageList.Add("PASS: Coordinates for this surface form a perfectly planar surface.");
                                report.TestPassedDict.Add(sb.surfaceIdRef, true);
                                continue;
                            }
                            //anti-parallel
                            else if (xProducts[j].X == -1 * xProducts[j + 1].X && xProducts[j].Y == -1 * xProducts[j + 1].Y && xProducts[j].Z == -1 * xProducts[j + 1].Z)
                            {
                                report.MessageList.Add("PASS: Coordinates for this surface form a perfectly planar surface.");
                                report.TestPassedDict.Add(sb.surfaceIdRef, true);
                                continue;
                            }
                            //I defined these tolerances myself.  Could this be done better?
                            else if (Math.Abs(xProducts[j].X) - Math.Abs(xProducts[j + 1].X) < 0.0001 && Math.Abs(xProducts[j].Y) - Math.Abs(xProducts[j + 1].Y) < 0.0001 &&
                                Math.Abs(xProducts[j].Z) - Math.Abs(xProducts[j + 1].Z) < 0.0001)
                            {
                                report.MessageList.Add("Coordinates for this surface form a nearly planar surface that is within allowable tolerances.");
                                report.TestPassedDict.Add(sb.surfaceIdRef, true);
                                continue;
                            }
                            else
                            {
                                report.MessageList.Add("NON PLANAR SURFACE DETECTED:  Coordinates for this surface do not appear to form a planar surface.");
                                report.TestPassedDict.Add(sb.surfaceIdRef, false);
                                spacepassorfail = false;
                            }
                        }
                    }
                    if (spacepassorfail)
                    {
                        report.TestPassedDict.Add(s.id, true);
                    }
                    else
                    {
                        report.TestPassedDict.Add(s.id, false);
                    }
                }
                
            }
            catch (Exception e)
            {
                //perhaps I want to log this for programmers to look at when they want
            }
            report.MessageList.Add("All test file's surfaces have polyloop descriptions that describe a planar surface.  Planar surface test succeeded.");
            report.passOrFail = true;
            return report;

        }

        public static DOEgbXMLReportingObj findStraySBVertices(string filelocation, DOEgbXMLReportingObj report)
        {
            report.testSummary = "";
            report.testReasoning = "";
            report.MessageList = new List<string>();
            try
            {
                int counter = 0;
                string specString = @"(\[.*]);(\[.*]);(\[.*])";
                string line;
                System.IO.StreamReader file = new StreamReader(filelocation);
                while ((line = file.ReadLine()) != null)
                {
                    Regex specRegex = new Regex(specString);
                    //parse the line
                    Match arrMatch = specRegex.Match(line);
                    if (arrMatch.Success)
                    {
                        if (counter == 0)
                        {
                            //header row
                            
                        }
                        else
                        {
                            // coordinateString = @"\[[-+]?([0-9]*\.[0-9]+|[0-9]+),[-+]?([0-9]*\.[0-9]+|[0-9]+),[-+]?([0-9]*\.[0-9]+|[0-9]+)]";
                            string coordinateString = @"(\[)(.*)(])";
                            string surfaceString = @"(\[)(.*)(])";
                            string boolString = @"(\[)(.*)(])";
                            Regex coordRegex = new Regex(coordinateString);
                            Match XYZMatch = coordRegex.Match(arrMatch.Groups[1].Value);
                            if (XYZMatch.Success)
                            {
                                //print something here for the user
                                List<string> coords = XYZMatch.Groups[2].Value.Split(',').ToList();


                                Regex surfRegex = new Regex(surfaceString);
                                Match surfMatch = surfRegex.Match(arrMatch.Groups[2].Value);
                                if (surfMatch.Success)
                                {
                                    //print something here for the user
                                    List<string> surf = surfMatch.Groups[2].Value.Split(',').ToList();
                                    if (surf.Count() >= 3)
                                    {
                                        //this is great
                                    }

                                    Regex boolRegex = new Regex(boolString);
                                    Match boolMatch = boolRegex.Match(arrMatch.Groups[3].Value);
                                    if (boolMatch.Success)
                                    {
                                        //print something here for the user
                                        List<string> bools = boolMatch.Groups[2].Value.Split(',').ToList();
                                        if (bools.Contains("False"))
                                        {
                                            //we have to take note of a potential problem
                                        }
                                    }
                                    else
                                    {
                                        //report that something has gone wrong
                                        //we need to receive a report about this somehow
                                    }

                                }
                                else
                                {
                                    //report that something has gone wrong
                                    //we need to receive a report about this somehow
                                }

                            }
                            else
                            {
                                //report that something has gone wrong
                                //we need to receive a report about this somehow
                            }

                            
                        }
                    }
                    else
                    {
                        //report that something has gone wrong
                        //we need to receive a report about this somehow
                    }
                    counter++;
                }
                
            }
            catch (Exception e)
            {
                //do something here
            }
            return report;
        }

    }





    
}
